<template>
  <div class="max-w-3xl mx-auto p-6">
    <h1 class="text-2xl font-semibold">GIF 制作（GIF Maker）</h1>
    <p class="mt-2 text-gray-600">将多张图片合成为动画 GIF。上传图片后可调整每帧时长、顺序，生成并下载 GIF。</p>

    <div class="mt-6 grid grid-cols-1 md:grid-cols-2 gap-6">
      <!-- 左侧：上传与帧设置 -->
      <div>
        <label class="block mb-2 text-sm font-medium text-gray-700">添加图片（可多选）</label>
        <div
          class="border-2 border-dashed border-gray-200 rounded-lg p-6 text-center hover:border-blue-300 transition-colors"
          @click="triggerFileInput"
        >
          <input ref="fileInput" type="file" accept="image/*" class="hidden" @change="onFileChange" multiple />
          <div v-if="frames.length === 0" class="text-gray-500">点击或拖拽上传多张图片，图片将按上传顺序成为帧。</div>
          <div v-else class="space-y-3">
            <div v-for="(f, i) in frames" :key="f.id" class="flex items-center space-x-3">
              <img :src="f.dataUrl" class="w-16 h-12 object-cover rounded" />
              <div class="flex-1">
                <div class="text-sm font-medium">帧 {{ i + 1 }}</div>
                <div class="text-xs text-gray-500">尺寸: {{ f.image.width }}x{{ f.image.height }} • 大小: {{ formatFileSize(f.size) }}</div>
                <div class="mt-1 flex items-center space-x-2">
                  <input type="number" v-model.number="f.delay" min="20" class="input-field w-24" />
                  <div class="text-xs text-gray-500">ms（每帧时长，最小 20ms）</div>
                </div>
              </div>
              <div class="flex flex-col space-y-1">
                <button @click.stop="moveUp(i)" :disabled="i===0" class="px-2 py-1 border rounded text-sm">上移</button>
                <button @click.stop="moveDown(i)" :disabled="i===frames.length-1" class="px-2 py-1 border rounded text-sm">下移</button>
                <button @click.stop="removeFrame(i)" class="px-2 py-1 border rounded text-sm text-red-600">删除</button>
              </div>
            </div>
          </div>
        </div>

        <div class="mt-4 space-y-3">
          <div>
            <label class="block text-sm text-gray-700 mb-1">全局设置</label>
            <div class="grid grid-cols-2 gap-2">
              <div>
                <label class="text-xs text-gray-600">循环次数（0 无限循环）</label>
                <input type="number" v-model.number="options.repeat" min="0" class="input-field w-full" />
              </div>
              <div>
                <label class="text-xs text-gray-600">质量（数值越低文件越小，1~30）</label>
                <input type="number" v-model.number="options.quality" min="1" max="30" class="input-field w-full" />
              </div>
            </div>
          </div>

          <div class="flex space-x-2 mt-3">
            <button @click="generateGif" :disabled="frames.length===0 || processing" class="primary-button">{{ processing ? (processingText) : '生成 GIF' }}</button>
            <button @click="reset" type="button" class="ml-2 inline-block px-4 py-2 border rounded text-sm" :disabled="processing">重置</button>
          </div>
          <div v-if="warnText" class="text-xs text-yellow-700 mt-2">{{ warnText }}</div>
        </div>
      </div>

      <!-- 右侧：预览与下载 -->
      <div>
        <label class="block mb-2 text-sm font-medium text-gray-700">预览 & 下载</label>
        <div class="border rounded-lg p-4">
          <div v-if="frames.length === 0 && !outputUrl" class="text-gray-500">尚未添加帧</div>
          <div v-else class="space-y-3">
            <div v-if="outputUrl">
              <div class="text-sm font-medium">生成预览</div>
              <img :src="outputUrl" alt="gif preview" class="max-h-60 object-contain rounded mt-2" />
            </div>
            <div v-else-if="frames.length > 0" class="text-gray-600">当前共有 {{ frames.length }} 帧，点击「生成 GIF」预览。</div>

            <div v-if="processing">
              <div class="text-sm">生成中：{{ Math.round(progress * 100) }}%</div>
              <div class="w-full bg-gray-200 rounded h-2 mt-2 overflow-hidden">
                <div :style="{ width: (progress * 100) + '%' }" class="h-2 bg-blue-500"></div>
              </div>
            </div>

            <div class="flex items-center justify-between">
              <div>
                <div v-if="outputSize" class="text-xs text-gray-600">生成大小：{{ formatFileSize(outputSize) }}</div>
              </div>
              <div>
                <button v-if="outputBlob" @click="downloadResult" class="primary-button">下载 GIF</button>
              </div>
            </div>
          </div>
        </div>
        <nuxt-link to="/image-tools" class="mt-4 inline-block text-blue-500">返回图片工具</nuxt-link>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { useTools } from '~/composables/useTools';

useHead({ title: 'GIF 制作 - 图片工具' });

const { readImageFile, formatFileSize: formatFileSizeUtil } = useTools();

const fileInput = ref(null);
const frames = ref([]);
const processing = ref(false);
const progress = ref(0);
const warnText = ref('');
const outputBlob = ref(null);
const outputUrl = ref(null);
const outputSize = ref(0);
const currentTaskId = ref(0);
const options = ref({ repeat: 0, quality: 10 });
const processingText = '生成中...';

const triggerFileInput = () => { if (fileInput.value) fileInput.value.click(); };

const loadGifShot = async () => {
  if (typeof window === 'undefined') throw new Error('仅在浏览器环境可用');
  if (window.gifshot) return window.gifshot;
  try {
    // 动态导入本地安装的 gifshot 包（仅在客户端）
    const mod = await import('gifshot');
    const gifshot = mod && (mod.default || mod.gifshot || window.gifshot);
    if (!gifshot && window.gifshot) return window.gifshot;
    if (!gifshot) throw new Error('gifshot 导入失败');
    // 确保在全局可用（某些版本依赖 window.gifshot）
    window.gifshot = gifshot;
    return gifshot;
  } catch (e) {
    // 如果直接导入失败，尝试从全局读取
    if (window.gifshot) return window.gifshot;
    throw e;
  }
};

const onFileChange = async (e) => {
  const list = Array.from(e.target.files || []);
  if (!list.length) return;
  warnText.value = '';
  for (const f of list) {
    if (!f.type.startsWith('image/')) continue;
    try {
      const res = await readImageFile(f);
      frames.value.push({ id: Date.now() + Math.random(), dataUrl: res.dataUrl, image: res.image, delay: 200, size: f.size });
    } catch (err) { console.error('读取图片失败', err); }
  }
  clearOutput();
};

const clearOutput = () => {
  try { if (outputUrl.value && outputUrl.value.startsWith('blob:')) URL.revokeObjectURL(outputUrl.value); } catch (_) {}
  outputBlob.value = null;
  outputUrl.value = null;
  outputSize.value = 0;
};

const moveUp = (i) => {
  if (i <= 0) return;
  const arr = frames.value;
  [arr[i - 1], arr[i]] = [arr[i], arr[i - 1]];
};

const moveDown = (i) => {
  const arr = frames.value;
  if (i >= arr.length - 1) return;
  [arr[i], arr[i + 1]] = [arr[i + 1], arr[i]];
};

const removeFrame = (i) => {
  const arr = frames.value;
  if (i < 0 || i >= arr.length) return;
  arr.splice(i, 1);
  clearOutput();
};

const formatFileSize = (n) => formatFileSizeUtil(n);

const reset = () => {
  frames.value = [];
  processing.value = false;
  progress.value = 0;
  warnText.value = '';
  currentTaskId.value++;
  clearOutput();
};

const generateGif = async () => {
  if (processing.value) return;
  if (frames.value.length === 0) return;
  let gifshot;
  try {
    gifshot = await loadGifShot();
  } catch (e) {
    warnText.value = 'gifshot.js 加载失败，请稍后重试';
    return;
  }

  const taskId = ++currentTaskId.value;
  processing.value = true;
  progress.value = 0;
  warnText.value = '';
  clearOutput();

  const MAX_FRAMES = 100;
  let useFrames = frames.value;
  if (useFrames.length > MAX_FRAMES) {
    warnText.value = '帧数过多，已限制为前 ' + MAX_FRAMES + ' 帧';
    useFrames = useFrames.slice(0, MAX_FRAMES);
  }

  // 以第一帧为基准尺寸并限制最大边长
  const baseW = useFrames[0].image.width;
  const baseH = useFrames[0].image.height;
  const MAX_DIM = 2000;
  const scale = Math.min(1, MAX_DIM / Math.max(baseW, baseH));
  const width = Math.max(1, Math.round(baseW * scale));
  const height = Math.max(1, Math.round(baseH * scale));

  // gifshot 支持统一的帧间隔（秒），不支持每帧单独延时。
  // 这里使用所有帧的平均延时作为整体间隔。
  const avgDelayMs = Math.max(20, Math.round(useFrames.reduce((s, f) => s + (f.delay || 200), 0) / useFrames.length));
  const intervalSec = Math.max(0.02, Math.round(avgDelayMs) / 1000);

  // quality 映射为 sampleInterval（值越大，质量越低但速度更快）
  const sampleInterval = Math.max(1, Math.min(30, options.value.quality || 10));

  const images = useFrames.map(f => f.dataUrl);

  try {
    gifshot.createGIF({
      images,
      gifWidth: width,
      gifHeight: height,
      interval: intervalSec,
      sampleInterval,
      numWorkers: 2,
      progressCallback: (p) => {
        if (currentTaskId.value !== taskId) return;
        progress.value = Math.max(0, Math.min(1, p));
      }
    }, async (obj) => {
      if (currentTaskId.value !== taskId) return;
      processing.value = false;
      if (obj.error) {
        warnText.value = '生成 GIF 失败：' + (obj.error || '未知错误');
        return;
      }
      // obj.image 是 data:image/gif;base64,...
      const dataUrl = obj.image;
      try {
        const res = await fetch(dataUrl);
        const blob = await res.blob();
        outputBlob.value = blob;
        try { if (outputUrl.value && outputUrl.value.startsWith('blob:')) URL.revokeObjectURL(outputUrl.value); } catch (_) {}
        outputUrl.value = URL.createObjectURL(blob);
        outputSize.value = blob.size || 0;
      } catch (e) {
        warnText.value = '处理生成结果失败';
      }
    });

    // gifshot 支持 progressCallback 设置为对象属性
    // 但某些版本只在内部调用。为保险起见，使用全局回调注册（部分版本支持 progressCallback）。
    if (gifshot && gifshot.createGIF && typeof gifshot.createGIF === 'function') {
      // 如果库支持 progressCallback，我们在 options 里传过就能更新；但上面回调已有最终处理。
      // 无需额外实现。
    }
  } catch (e) {
    processing.value = false;
    warnText.value = '生成 GIF 失败：' + (e && e.message ? e.message : '未知错误');
  }
};

const downloadResult = () => {
  if (!outputBlob.value && !outputUrl.value) return;
  if (outputBlob.value) {
    const a = document.createElement('a');
    a.href = outputUrl.value;
    a.download = 'animated.gif';
    document.body.appendChild(a);
    a.click();
    a.remove();
  } else if (outputUrl.value) {
    const a = document.createElement('a');
    a.href = outputUrl.value;
    a.download = 'animated.gif';
    document.body.appendChild(a);
    a.click();
    a.remove();
  }
};

</script>